package instruction

import (
	"gitee.com/microwww/jvm-go/jvm/rtda"
	"gitee.com/microwww/jvm-go/jvm/tool"
)

type Noop struct {
}

func (f *Noop) FetchOperands(*tool.Buffer) {
	// nothing to do
}

func (f *Noop) Execute(*rtda.MethodFrame) {
	// nothing to do
}

type offsetInstruct struct {
	Offset int
}

func (f *offsetInstruct) FetchOperands(bf *tool.Buffer) {
	v := bf.ReadInt16() // 大部分是 int16, GOTO_W int32, 所以 PC 的类型是 int32, !!! 注意这里可以是负数 !!!
	f.Offset = int(v)
}

func (f *offsetInstruct) Branch(fm *rtda.MethodFrame) {
	Branch(fm, f.Offset)
}

func Branch(fm *rtda.MethodFrame, offset int) { // offset 可以为负数 , int16 的类型
	pc := fm.Thread().PC()
	npc := pc + offset
	fm.SetNextPC(npc)
}

// const 指令

type A_const_NULL struct {
	Noop
}

func (f *A_const_NULL) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushRef(nil)
}

type D_const_0 struct {
	Noop
}

func (f *D_const_0) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushDouble(0.0)
}

type D_const_1 struct {
	Noop
}

func (f *D_const_1) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushDouble(1.0)
}

type F_const_0 struct {
	Noop
}

func (f *F_const_0) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushFloat(0.0)
}

type F_const_1 struct {
	Noop
}

func (f *F_const_1) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushFloat(1.0)
}

type F_const_2 struct {
	Noop
}

func (f *F_const_2) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushFloat(2.0)
}

type I_const_M1 struct {
	Noop
}

func (f *I_const_M1) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(-1)
}

type I_const_0 struct {
	Noop
}

func (f *I_const_0) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(0)
}

type I_const_1 struct {
	Noop
}

func (f *I_const_1) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(1)
}

type I_const_2 struct {
	Noop
}

func (f *I_const_2) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(2)
}

type I_const_3 struct {
	Noop
}

func (f *I_const_3) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(3)
}

type I_const_4 struct {
	Noop
}

func (f *I_const_4) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(4)
}

type I_const_5 struct {
	Noop
}

func (f *I_const_5) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(5)
}

type L_const_0 struct {
	Noop
}

func (f *L_const_0) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushLong(0)
}

type L_const_1 struct {
	Noop
}

func (f *L_const_1) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushLong(1)
}

// b-i-push, s-i-push

type B_i_push struct {
	val int8
}

func (f *B_i_push) FetchOperands(bf *tool.Buffer) {
	v, _ := bf.ReadByte()
	f.val = int8(v)
}
func (f *B_i_push) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(int32(f.val))
}

type S_i_push struct {
	val int16
}

func (f *S_i_push) FetchOperands(bf *tool.Buffer) {
	v1, _ := bf.ReadByte()
	v2, _ := bf.ReadByte()
	f.val = int16(v1)<<8 | int16(v2)
}
func (f *S_i_push) Execute(fr *rtda.MethodFrame) {
	fr.OperationStack().PushInt(int32(f.val))
}

// 局部变量中 加载指令

type _8_fetch struct {
	Index uint
}

func (f *_8_fetch) FetchOperands(bf *tool.Buffer) {
	v, _ := bf.ReadByte()
	f.Index = uint(v)
}

type _16_fetch struct {
	Index uint
}

func (f *_16_fetch) FetchOperands(bf *tool.Buffer) {
	v1, _ := bf.ReadByte()
	v2, _ := bf.ReadByte()
	f.Index = uint(v1)<<8 | uint(v2)
}

func loadI2stack(fr *rtda.MethodFrame, index uint) {
	v := fr.LocalVar().GetInt(index)
	fr.OperationStack().PushInt(v)
}

func loadL2stack(fr *rtda.MethodFrame, index uint) {
	v := fr.LocalVar().GetLong(index)
	fr.OperationStack().PushLong(v)
}

func loadF2stack(fr *rtda.MethodFrame, index uint) {
	v := fr.LocalVar().GetFloat(index)
	fr.OperationStack().PushFloat(v)
}

func loadD2stack(fr *rtda.MethodFrame, index uint) {
	v := fr.LocalVar().GetDouble(index)
	fr.OperationStack().PushDouble(v)
}

func loadA2stack(fr *rtda.MethodFrame, index uint) {
	v := fr.LocalVar().GetRef(index)
	fr.OperationStack().PushRef(v)
}

type ILoad struct {
	_8_fetch
}

func (f *ILoad) Execute(fr *rtda.MethodFrame) {
	loadI2stack(fr, f.Index)
}

type ILoad0 struct {
	Noop
}

func (f *ILoad0) Execute(fr *rtda.MethodFrame) {
	loadI2stack(fr, 0)
}

type ILoad1 struct {
	Noop
}

func (f *ILoad1) Execute(fr *rtda.MethodFrame) {
	loadI2stack(fr, 1)
}

type ILoad2 struct {
	Noop
}

func (f *ILoad2) Execute(fr *rtda.MethodFrame) {
	loadI2stack(fr, 2)
}

type ILoad3 struct {
	Noop
}

func (f *ILoad3) Execute(fr *rtda.MethodFrame) {
	loadI2stack(fr, 3)
}

type LLoad struct {
	_8_fetch
}

func (f *LLoad) Execute(fr *rtda.MethodFrame) {
	loadL2stack(fr, f.Index)
}

type LLoad0 struct {
	Noop
}

func (f *LLoad0) Execute(fr *rtda.MethodFrame) {
	loadL2stack(fr, 0)
}

type LLoad1 struct {
	Noop
}

func (f *LLoad1) Execute(fr *rtda.MethodFrame) {
	loadL2stack(fr, 1)
}

type LLoad2 struct {
	Noop
}

func (f *LLoad2) Execute(fr *rtda.MethodFrame) {
	loadL2stack(fr, 2)
}

type LLoad3 struct {
	Noop
}

func (f *LLoad3) Execute(fr *rtda.MethodFrame) {
	loadI2stack(fr, 3)
}

type FLoad struct {
	_8_fetch
}

func (f *FLoad) Execute(fr *rtda.MethodFrame) {
	loadF2stack(fr, f.Index)
}

type FLoad0 struct {
	Noop
}

func (f *FLoad0) Execute(fr *rtda.MethodFrame) {
	loadF2stack(fr, 0)
}

type FLoad1 struct {
	Noop
}

func (f *FLoad1) Execute(fr *rtda.MethodFrame) {
	loadF2stack(fr, 1)
}

type FLoad2 struct {
	Noop
}

func (f *FLoad2) Execute(fr *rtda.MethodFrame) {
	loadF2stack(fr, 2)
}

type FLoad3 struct {
	Noop
}

func (f *FLoad3) Execute(fr *rtda.MethodFrame) {
	loadF2stack(fr, 3)
}

type DLoad struct {
	_8_fetch
}

func (f *DLoad) Execute(fr *rtda.MethodFrame) {
	loadD2stack(fr, f.Index)
}

type DLoad0 struct {
	Noop
}

func (f *DLoad0) Execute(fr *rtda.MethodFrame) {
	loadD2stack(fr, 0)
}

type DLoad1 struct {
	Noop
}

func (f *DLoad1) Execute(fr *rtda.MethodFrame) {
	loadD2stack(fr, 1)
}

type DLoad2 struct {
	Noop
}

func (f *DLoad2) Execute(fr *rtda.MethodFrame) {
	loadD2stack(fr, 2)
}

type DLoad3 struct {
	Noop
}

func (f *DLoad3) Execute(fr *rtda.MethodFrame) {
	loadD2stack(fr, 3)
}

type ALoad struct {
	_8_fetch
}

func (f *ALoad) Execute(fr *rtda.MethodFrame) {
	loadA2stack(fr, f.Index)
}

type ALoad0 struct {
	Noop
}

func (f *ALoad0) Execute(fr *rtda.MethodFrame) {
	loadA2stack(fr, 0)
}

type ALoad1 struct {
	Noop
}

func (f *ALoad1) Execute(fr *rtda.MethodFrame) {
	loadA2stack(fr, 1)
}

type ALoad2 struct {
	Noop
}

func (f *ALoad2) Execute(fr *rtda.MethodFrame) {
	loadA2stack(fr, 2)
}

type ALoad3 struct {
	Noop
}

func (f *ALoad3) Execute(fr *rtda.MethodFrame) {
	loadA2stack(fr, 3)
}

// 局部变量中 存储

func storeI2local(fr *rtda.MethodFrame, index uint) {
	v := fr.OperationStack().PopInt()
	fr.LocalVar().SetInt(index, v)
}
func storeL2local(fr *rtda.MethodFrame, index uint) {
	v := fr.OperationStack().PopLong()
	fr.LocalVar().SetLong(index, v)
}
func storeF2local(fr *rtda.MethodFrame, index uint) {
	v := fr.OperationStack().PopFloat()
	fr.LocalVar().SetFloat(index, v)
}
func storeD2local(fr *rtda.MethodFrame, index uint) {
	v := fr.OperationStack().PopDouble()
	fr.LocalVar().SetDouble(index, v)
}
func storeA2local(fr *rtda.MethodFrame, index uint) {
	v := fr.OperationStack().PopRef()
	fr.LocalVar().SetRef(index, v)
}

type IStore struct {
	_8_fetch
}

func (f *IStore) Execute(fr *rtda.MethodFrame) {
	storeI2local(fr, f.Index)
}

type IStore0 struct {
	Noop
}

func (f *IStore0) Execute(fr *rtda.MethodFrame) {
	storeI2local(fr, 0)
}

type IStore1 struct {
	Noop
}

func (f *IStore1) Execute(fr *rtda.MethodFrame) {
	storeI2local(fr, 1)
}

type IStore2 struct {
	Noop
}

func (f *IStore2) Execute(fr *rtda.MethodFrame) {
	storeI2local(fr, 2)
}

type IStore3 struct {
	Noop
}

func (f *IStore3) Execute(fr *rtda.MethodFrame) {
	storeI2local(fr, 3)
}

type LStore struct {
	_8_fetch
}

func (f *LStore) Execute(fr *rtda.MethodFrame) {
	storeL2local(fr, f.Index)
}

type FStore struct {
	_8_fetch
}

func (f *FStore) Execute(fr *rtda.MethodFrame) {
	storeF2local(fr, f.Index)
}

type DStore struct {
	_8_fetch
}

func (f *DStore) Execute(fr *rtda.MethodFrame) {
	storeD2local(fr, f.Index)
}

type AStore struct {
	_8_fetch
}

func (f *AStore) Execute(fr *rtda.MethodFrame) {
	storeA2local(fr, f.Index)
}

type LStore0 struct {
	Noop
}

func (f *LStore0) Execute(fr *rtda.MethodFrame) {
	storeL2local(fr, 0)
}

type LStore1 struct {
	Noop
}

func (f *LStore1) Execute(fr *rtda.MethodFrame) {
	storeL2local(fr, 1)
}

type LStore2 struct {
	Noop
}

func (f *LStore2) Execute(fr *rtda.MethodFrame) {
	storeL2local(fr, 2)
}

type LStore3 struct {
	Noop
}

func (f *LStore3) Execute(fr *rtda.MethodFrame) {
	storeL2local(fr, 3)
}

type FStore0 struct {
	Noop
}

func (f *FStore0) Execute(fr *rtda.MethodFrame) {
	storeF2local(fr, 0)
}

type FStore1 struct {
	Noop
}

func (f *FStore1) Execute(fr *rtda.MethodFrame) {
	storeF2local(fr, 1)
}

type FStore2 struct {
	Noop
}

func (f *FStore2) Execute(fr *rtda.MethodFrame) {
	storeF2local(fr, 2)
}

type FStore3 struct {
	Noop
}

func (f *FStore3) Execute(fr *rtda.MethodFrame) {
	storeF2local(fr, 3)
}

type DStore0 struct {
	Noop
}

func (f *DStore0) Execute(fr *rtda.MethodFrame) {
	storeD2local(fr, 0)
}

type DStore1 struct {
	Noop
}

func (f *DStore1) Execute(fr *rtda.MethodFrame) {
	storeD2local(fr, 1)
}

type DStore2 struct {
	Noop
}

func (f *DStore2) Execute(fr *rtda.MethodFrame) {
	storeD2local(fr, 2)
}

type DStore3 struct {
	Noop
}

func (f *DStore3) Execute(fr *rtda.MethodFrame) {
	storeD2local(fr, 3)
}

type AStore0 struct {
	Noop
}

func (f *AStore0) Execute(fr *rtda.MethodFrame) {
	storeA2local(fr, 0)
}

type AStore1 struct {
	Noop
}

func (f *AStore1) Execute(fr *rtda.MethodFrame) {
	storeA2local(fr, 1)
}

type AStore2 struct {
	Noop
}

func (f *AStore2) Execute(fr *rtda.MethodFrame) {
	storeA2local(fr, 2)
}

type AStore3 struct {
	Noop
}

func (f *AStore3) Execute(fr *rtda.MethodFrame) {
	storeA2local(fr, 3)
}

// 栈指令

type POP struct {
	Noop
}

func (f *POP) Execute(fm *rtda.MethodFrame) {
	fm.OperationStack().PopSlot()
}

type POP2 struct {
	Noop
}

func (f *POP2) Execute(fm *rtda.MethodFrame) {
	fm.OperationStack().PopSlot()
	fm.OperationStack().PopSlot()
}

type DUP struct { // DUP_X1,DUP_X2, DUP2, DUP2_X1, DUP2_X2
	Noop
}

func (f *DUP) Execute(fm *rtda.MethodFrame) {
	stack := fm.OperationStack()
	s := stack.PopSlot()
	stack.PushSlot(s)
	stack.PushSlot(s)
}

type Swap struct { // DUP_X1,DUP_X2, DUP2, DUP2_X1, DUP2_X2
	Noop
}

func (f *Swap) Execute(fm *rtda.MethodFrame) {
	stack := fm.OperationStack()
	s1 := stack.PopSlot()
	s2 := stack.PopSlot()
	stack.PushSlot(s1)
	stack.PushSlot(s2)
}
